home *** CD-ROM | disk | FTP | other *** search
/ Maclife 157 / MACLIFE157-2001-09.ISO.7z / MACLIFE157-2001-09.ISO / Linux / MacOS Tools / BootX 1.2.2 / Sources / lib / MoreCFMPatches / MoreCFMPatches.h < prev    next >
Text File  |  2001-07-23  |  12KB  |  316 lines

  1. /*
  2.     File:        MoreCFMPatches.h
  3.  
  4.     Contains:    Interface to CFM patching technology.
  5.  
  6.     Written by:    Quinn
  7.  
  8.     Copyright:    Copyright ゥ 1998-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.  
  20.          <1>     16/3/99    Quinn   First checked in.
  21. */
  22.  
  23. #pragma once
  24.  
  25. /////////////////////////////////////////////////////////////////
  26.  
  27. // MoreIsBetter Setup
  28.  
  29. #include "MoreSetup.h"
  30.  
  31. // Standard Mac OS interfaces
  32.  
  33. #include <MacTypes.h>
  34.  
  35. /////////////////////////////////////////////////////////////////
  36. // Using MoreCFMPatches
  37.  
  38. // This CFM patching technology works by monkeying with transition
  39. // vectors, henceforth known as TVectors, in non-obvious ways.
  40. // To use it succesfully, you must know something about TVectors.
  41. // For complete information, I suggest the book "Mac OS Runtime
  42. // Architectures", available from <http://www.apple.com/developer/>.
  43. // However, the following points are especially important:
  44. //
  45. // 1. On CFM architectures, all exported functions are called
  46. //    by means of a TVector.  The exporter exports a TVector
  47. //    in its data section, the importer imports the address of
  48. //    the TVector as a pointer in its data section.  When
  49. //    the importer calls the function, it does so by calling
  50. //    through this TVector pointer.
  51. //
  52. // 2. Likewise, all routine pointers are not actually pointers
  53. //    to code, but pointers to TVectors.
  54. //
  55. // 3. TVectors are typically two words long, the first word being
  56. //    a pointer to the code and the second word being a pointer to
  57. //    the callee's TOC (ie somewhere in the callee's data section)
  58. //    However this is not  a requirement.  The only requirements are:
  59. //      a) the first word must point to the code,
  60. //      b) the caller must load the second word into R2, and
  61. //      c) the caller must load R12 with a pointer to the TVector itself.
  62. //         [This allows the callee to extract any extra information
  63. //          it cares to store in the TVector.]
  64. //    This patching technology maintains all these invariants.
  65. //    Beware of cheap imitations!
  66. //
  67. // Using this library is very easy.  Just follow the 5 easy
  68. // steps:
  69. //
  70. //   i. Write your patch routine to have exactly the same
  71. //      calling conventions as the routine you are going to patch.
  72. //
  73. //        extern pascal void OriginalRoutine(char *param);
  74. //
  75. //        extern pascal void MyPatch(char *param)
  76. //        {
  77. //            [...do stuff...]
  78. //        }
  79. //
  80. //  ii. Call MorePatchTVector to add your patch to the list
  81. //      of patches on the original routine.  Remember, a C
  82. //      function pointer is a pointer to a transition vector,
  83. //      so you can just cast a pointer to the original routine
  84. //      to a TVector.  Neat huh?
  85. //
  86. //        err = MorePatchTVector((TVector *) OriginalRoutine,
  87. //                               (TVector *) MyPatch,
  88. //                               kMyCreator,
  89. //                               nil);
  90. //
  91. // iii. Don't forget to include a useful creator code so that
  92. //      you (and Apple) can manage your patches.
  93. //
  94. //  iv. If you need to call through to the original routine,
  95. //      just cast gMoreCFMPatchesCallThrough to the appropriate
  96. //      C routine pointer type and call it.
  97. //
  98. //        typedef pascal void (*OriginalRoutineProc)(char *param);
  99. //
  100. //        extern pascal void MyPatch(char *param)
  101. //        {
  102. //            [...do 'head' patch stuff...]
  103. //            ((OriginalRoutineProc) gMoreCFMPatchesCallThrough)(param);
  104. //            [...do 'tail' patch stuff...]
  105. //        }
  106. //
  107. //      You use the same routine pointer for all patches in all
  108. //      patch chains.  The clever run-time implementation figures
  109. //      out what to call when.  But remember:
  110. //
  111. //      a. you must call through from the mainline of your
  112. //         patch routine, not from a routine that your patch
  113. //         routine has called, and
  114. //
  115. //      b. for gMoreCFMPatchesCallThrough to work properly, the fragment
  116. //         containing "MoreCFMPatches.c" must remain in memory as long
  117. //         as the patch code that might actually call it.  Don't
  118. //         try to call gMoreCFMPatchesCallThrough after unloading
  119. //         "MoreCFMPatches.c".
  120. //
  121. //   v. Link with the MoreCFMPatchesLib.stub library.  You must
  122. //        weak link with this stub library.  Doing so allows future
  123. //        system software to override the behaviour of this patching
  124. //        module without any special hackery.  The module is designed
  125. //        such that, if the weak link succeeds, all routines in this
  126. //        module will call through their equivalent routines in the
  127. //        library.
  128. //    
  129. //            IMPORTANT:
  130. //            *NEVER* build MoreCFMPatches into a CFM shared library and
  131. //            install it in the Extensions folder.  This module is meant
  132. //            to be linked into your application as C source code.
  133. //            Linking with a stub library is done to allow some future
  134. //            system software version of this code to override the
  135. //            behaviour of this code in a compatible fashion.
  136. //        
  137. //  vi. Finally, and this is the big one, you must remember that
  138. //      TVectors are exported out of a fragment's *data* section.
  139. //      Fragments may use a shared data section, or a per-context
  140. //      data section.  Fragments with a shared data section only
  141. //      have a single set of TVectors and are easy to patch.  However,
  142. //      per-context fragments export a different set of TVectors
  143. //      for each context and, if you want your patch to have global
  144. //      effect, you must patch the TVectors in each context.  Urgh.
  145. //      Furthermore, there's no easy way to determine whether a
  146. //      fragment is per-context or globally shared.  You just have
  147. //      to "DumpPEF" it and check out the flag.  And there's no
  148. //      guarantee that a particular fragment will not switch from
  149. //      being one to the other.
  150. //
  151. //        Beyond that, you should be warned that patching a TVector
  152. //        with a TVector modifies both TVectors.  So if you're
  153. //        patching a per-context library, you must patch it with
  154. //        a TVector from a per-context library.
  155. //
  156. //      Hey, you knew the job was dangerous when you took it.
  157.  
  158. /////////////////////////////////////////////////////////////////
  159. // Error Codes
  160.  
  161. enum {
  162.     kVectorNotPatchedByUsErr = -680,
  163.         // This error can be returned by various routines when
  164.         // you attempt to manipulate patches on a TVector that
  165.         // either a) wasn't patched by MorePatchTVector (or compatible
  166.         // routine), or b) has been over-patched by an incompatible
  167.         // TVector patching technology.
  168.         
  169.     kPatchNotFoundInPatchIslandErr = -681,
  170.         // This error can be returned by MoreUnpatchTVector when
  171.         // you attempt to unpatch a TVector that was patched with
  172.         // a compatible TVector patching techology but whose
  173.         // patchTVectorToRemove wasn't found in the list of patches.
  174.         // If you successfully called MorePatchTVector, this typically
  175.         // implies either a) you're not passing in the same TVector
  176.         // in patchTVectorToRemove as you passed in to the
  177.         // patchTVectorToAdd parameter of MorePatchTVector, or b)
  178.         // someone overpatched your original patch with an incompatible
  179.         // patching technology and then someone else overpatched that
  180.         // with a compatible patching technology.  Urgh.
  181.     
  182.     kTVectorAlreadyPatchedByYouErr = -682,
  183.         // This error is return by MorePatchTVector when the TVector
  184.         // being patched has already been patched with the supplied
  185.         // patch TVector.
  186.     
  187.     kPatchNotFoundErr = -683,
  188.     
  189.     kPatchInfoOverrunErr = -684
  190. };
  191.  
  192. /////////////////////////////////////////////////////////////////
  193. // TVector Structure
  194.  
  195. // TVector represents the CFM "transition vector".  See
  196. // "Mac OS Runtime Architectures" for more details about
  197. // transition vectors.
  198.  
  199. // The pragma align isn't strictly speaking necessary but the
  200. // TVector structure is graven in stone, never to change, so
  201. // let's play by the rules and declare it that way.
  202.  
  203. #if PRAGMA_STRUCT_ALIGN
  204.     #pragma options align=mac68k
  205. #elif PRAGMA_STRUCT_PACKPUSH
  206.     #pragma pack(push, 2)
  207. #elif PRAGMA_STRUCT_PACK
  208.     #pragma pack(2)
  209. #endif
  210.  
  211. struct TVector {
  212.     void *codePointer;
  213.     // ... extra fields are compiler specific
  214. };
  215. typedef struct TVector TVector, *TVectorPtr;
  216.  
  217. #if PRAGMA_STRUCT_ALIGN
  218.     #pragma options align=reset
  219. #elif PRAGMA_STRUCT_PACKPUSH
  220.     #pragma pack(pop)
  221. #elif PRAGMA_STRUCT_PACK
  222.     #pragma pack()
  223. #endif
  224.  
  225. #ifdef __cplusplus
  226. extern "C" {
  227. #endif
  228.  
  229. /////////////////////////////////////////////////////////////////
  230. // Interface to Patching Code
  231.  
  232. extern ProcPtr  gMoreCFMPatchesCallThrough;
  233.     // This routine pointer is used to call through to the
  234.     // previous routine in the patch chain.  Just cast it
  235.     // to the appropriate C function pointer type and call it.
  236.  
  237. extern pascal OSStatus MorePatchTVector(TVector *tVectorToPatch,
  238.                             TVector *patchTVectorToAdd,
  239.                             OSType  creator,
  240.                             void    *refcon);
  241.     // Patch the routine whose TVector is tVectorToPatch with
  242.     // a routine whose TVector is patchTVectorToAdd.  creator
  243.     // and refcon are extra data associated with the patch
  244.     // that is not intepreted by this module.  You should
  245.     // pass a registered creator code into creator and you
  246.     // can pass whatever you like into refcon.
  247.     //
  248.     // The creator helps to identify which software has patched
  249.     // which routines, which in turns helps you (and Apple) to
  250.     // debug weird patching conflicts.
  251.     //
  252.     // patchTVectorToAdd must point to a TVector for a routine
  253.     // whose prototype is *exactly* the same as the prototype
  254.     // of the routine whose TVector is tVectorToPatch.
  255.     //
  256.     // If you intend to patch a routine globally, you must call
  257.     // this for every instance of the TVector tVectorToPatch
  258.     // that's created.  See above for details.
  259.     //
  260.     // The only likely error codes include kTVectorAlreadyPatchedByYouErr
  261.     // (tVectorToPatch is already patched by tPatchTVectorToAdd) and
  262.     // Memory Manager errors, specifically memFullErr.
  263.  
  264. extern pascal OSStatus MoreUnpatchTVector(TVector *tVectorToUnpatch,
  265.                             TVector *patchTVectorToRemove);
  266.     // Remove the routine whose TVector is patchTVectorToRemove
  267.     // from the list of patches on tVectorToUnpatch.  The likely
  268.     // error codes include kVectorNotPatchedByUsErr and
  269.     // kPatchNotFoundInPatchIslandErr, both of which are explained
  270.     // above.
  271.  
  272. /////////////////////////////////////////////////////////////////
  273. // Debugging/Sanity Checking Routines
  274.  
  275. extern pascal OSStatus MoreCountPatches(TVector *tVector, ItemCount *count);
  276.     // Counts the number of patches associated with the supplied TVector.
  277.     // Returns kVectorNotPatchedByUsErr if the TVector hasn't been
  278.     // patched by us.
  279.     
  280. //    infoKind                               bufferSize
  281.  
  282. enum {
  283.     kPatchInfoCreator = 'crea',            // sizeof(OSType)
  284.     kPatchInfoTVector = 'tvec',            // sizeof(TVector *)
  285.     kPatchInfoRefcon  = 'refc'            // sizeof(void *)
  286. };
  287.  
  288. extern pascal OSStatus MoreGetIndexedPatchInfo(TVector *tVector, ItemCount index,
  289.                             OSType infoKind, void *buffer, ByteCount bufferSize);
  290.     // Returns information about the index'th patch applied
  291.     // to the TVector.  index is one based, and must be in the range
  292.     // 1 through the value returned by MoreCountPatches.  infoKind
  293.     // specifies the type of information you're interested in,
  294.     // and must be one of the OSTypes in the enumeration above.
  295.     // buffer must point to a buffer where the information is
  296.     // placed.  bufferSize must be the size of the buffer pointed
  297.     // to by buffer.
  298.     //
  299.     // The routine returns kPatchNotFoundErr if index is out
  300.     // of bounds.
  301.     //
  302.     // The routine returns kPatchInfoOverrunErr if the buffer
  303.     // is too small to accept all the information, but it
  304.     // also fills in the first bufferSize bytes of the buffer.
  305.     //
  306.     // Note for the future: If the information is variable
  307.     // length (a string perhaps), the returned information
  308.     // must include a description of the true length, otherwise
  309.     // there's no way for the client to know how much of
  310.     // the buffer is valid if the client supplied a bigger
  311.     // buffer than was necessary.
  312.     
  313. #ifdef __cplusplus
  314. }
  315. #endif
  316.